5-2 tapable进阶:webpack核心库事件控制示例
各类 Hook 实践
SyncHook —— 基础同步钩子
最简单的 Hook,按注册顺序依次执行回调,忽略返回值。
const { SyncHook } = require('tapable');
const hook = new SyncHook(['name']);
hook.tap('Step1', (name) => {
console.log(`Step1: Hello ${name}`);
});
hook.tap('Step2', (name) => {
console.log(`Step2: World ${name}`);
});
hook.call('Webpack');
// 输出:
// Step1: Hello Webpack
// Step2: World Webpack
javascript
SyncBailHook —— 中断式同步钩子
只要有一个回调返回了非 undefined 的值,后续回调不再执行。适用于"条件检查"场景。
const { SyncBailHook } = require('tapable');
const hook = new SyncBailHook(['age']);
hook.tap('Check1', (age) => {
if (age < 18) {
return 'too young'; // 返回非 undefined,后续不再执行
}
return undefined; // 继续执行下一个
});
hook.tap('Check2', (age) => {
console.log(`Age ${age} passed all checks`);
});
const result = hook.call(16);
console.log(result); // 'too young'
javascript
在 Webpack 中,SyncBailHook 常用于 shouldEmit 钩子——如果某个 Plugin 返回 false,Webpack 就不会执行 emit 阶段。
SyncWaterfallHook —— 瀑布式同步钩子
上一个回调的返回值作为下一个回调的第一个参数,形成数据处理管道。
const { SyncWaterfallHook } = require('tapable');
const hook = new SyncWaterfallHook(['value']);
hook.tap('Double', (value) => {
return value * 2;
});
hook.tap('AddTen', (value) => {
return value + 10;
});
hook.tap('Format', (value) => {
return `Result: ${value}`;
});
const result = hook.call(5);
console.log(result); // 'Result: 20' (5*2=10, 10+10=20)
javascript
AsyncSeriesHook —— 异步串行钩子
多个异步回调按注册顺序依次执行,每个回调必须完成后才执行下一个。
const { AsyncSeriesHook } = require('tapable');
const hook = new AsyncSeriesHook(['data']);
hook.tapAsync('FetchUser', (data, callback) => {
setTimeout(() => {
console.log('User fetched');
callback();
}, 1000);
});
hook.tapAsync('FetchPosts', (data, callback) => {
setTimeout(() => {
console.log('Posts fetched');
callback();
}, 500);
});
hook.callAsync({ userId: 1 }, (err) => {
console.log('All done');
});
// 输出(间隔约1.5秒):
// User fetched
// Posts fetched
// All done
javascript
AsyncParallelHook —— 异步并行钩子
多个异步回调同时执行,全部完成后触发最终回调。
const { AsyncParallelHook } = require('tapable');
const hook = new AsyncParallelHook(['data']);
hook.tapPromise('TaskA', (data) => {
return new Promise((resolve) => {
setTimeout(() => {
console.log('TaskA done');
resolve();
}, 1000);
});
});
hook.tapPromise('TaskB', (data) => {
return new Promise((resolve) => {
setTimeout(() => {
console.log('TaskB done');
resolve();
}, 500);
});
});
hook.promise({}).then(() => {
console.log('All parallel tasks done');
});
// 输出(间隔约1秒,因为并行执行):
// TaskB done
// TaskA done
// All parallel tasks done
javascript
Hook 类型选择指南
| 需求 | 推荐 Hook |
|---|---|
| 简单通知,不关心返回值 | SyncHook |
| 条件检查,可能中断流程 | SyncBailHook |
| 数据转换管道 | SyncWaterfallHook |
| 异步任务按顺序执行 | AsyncSeriesHook |
| 异步任务同时执行 | AsyncParallelHook |
| 异步条件检查 | AsyncSeriesBailHook |
| 异步数据管道 | AsyncSeriesWaterfallHook |
参考资源
- tapable GitHub - 源码和文档
- Webpack Writing a Plugin - 插件开发指南
↑